package com.tarena.lbs.basic.web.service;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.basic.web.repository.AdminRepository;
import com.tarena.lbs.basic.web.repository.BusinessCategoryRepository;
import com.tarena.lbs.basic.web.repository.BusinessRepository;

import com.tarena.lbs.basic.web.repository.StoreRepository;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.common.security.utils.LbsSecurityContenxt;
import com.tarena.lbs.pojo.attach.param.PicUpdateParam;
import com.tarena.lbs.pojo.basic.param.BusinessParam;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.basic.po.BusinessCategoryPO;
import com.tarena.lbs.pojo.basic.po.BusinessPO;
import com.tarena.lbs.pojo.basic.po.StorePO;
import com.tarena.lbs.pojo.basic.query.BusinessQuery;

import com.tarena.lbs.pojo.basic.vo.BusiStoreVO;
import com.tarena.lbs.pojo.basic.vo.BusinessCategoryVO;
import com.tarena.lbs.pojo.basic.vo.BusinessVO;

import com.tarena.lbs.pojo.basic.vo.StoreVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BusinessService {
    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private BusinessCategoryRepository businessCategoryRepository;
    @Autowired
    private AdminRepository adminRepository;
    @Autowired
    private StoreRepository storeRepository;
    public PageResult<BusinessVO> businessPage(BusinessQuery query) throws BusinessException {
        /**
         * 根据登录用户角色 查询对应的商家列表
         */
        //为店铺绑定商家 查询商家列表 引如数据权限业务逻辑
        //a.获取反问发起的用户 认证对象
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        //b.判断空 读取角色 根据角色判断是否查询条件query 要补充businessId
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户解析认证失败"));
        Integer adminId = userPrinciple.getId();//当前登录用户id
        Roles role = userPrinciple.getRole();//当前登录角色
        if (role==Roles.SHOP){
            AdminPO adminPO = adminRepository.getAdminById(adminId);
            Asserts.isTrue(adminPO==null,new BusinessException("-2","商家信息不存在"));
            query.setBusinessId(adminPO.getBusinessId());
        }

        //1.准备一个pageResult 返回对象
        PageResult<BusinessVO> voPages = new PageResult<>();
        //2.直接调用仓储层 查询分页数据 数据返回值是PageInfo 包含了一个分页数据的所有属性 pageNum pageSize total
        PageInfo<BusinessPO> pageInfo =businessRepository.businessPageHelper(query);
        log.info("当前分页查询的pageInfo：{}",pageInfo);
        //3、将pageInfo中的属性封装到voPage中
        voPages.setTotal(pageInfo.getTotal());
        voPages.setPageNo(pageInfo.getPageNum());
        voPages.setPageSize(pageInfo.getPageSize());
        //4保持封装list的判断 如果list非空 元素个数>0 才能封装转化
        List<BusinessVO> vos = null;
        if (CollectionUtils.isNotEmpty(pageInfo.getList())) {
            List<BusinessPO> pos = pageInfo.getList();
            //将pos 转换成vos 多对多的转换
            vos = pos.stream().map(po -> {
                BusinessVO vo = new BusinessVO();
                BeanUtils.copyProperties(po, vo);
                return vo;
            }).collect(Collectors.toList());
        }
        voPages.setObjects(vos);
        return voPages;
    }

    /*public PageResult<BusinessVO> businessPage(BusinessQuery query){
        //业务层 需要根据入参条件query 查询数据库lbs_business的满足条件的商家数据
        //然后按照分页处理
        PageResult<BusinessVO> voPages = new PageResult<>();
        //voPages分页对象 需要5个属性 total 查询条件对应总数 objects 当前页的列表
        //pageNo 不用查询 query 自带 pageSize 不用查询 query自带 totalPage 不用查 只要pageResult装配好了total和pageSize
        //totalPage=total%pageSize==0?total/pageSize:(total/pageSize)+1;
        // total=505 pageSize-10 totalPage=51
        //调用仓储层 封装分页条件 单独查 第一次查total 第二次查分页
        Long total = businessRepository.businessTotal(query);
        voPages.setTotal(total);
        voPages.setPageNo(query.getPageNo());
        voPages.setPageSize(query.getPageSize());
        // 调用仓储层 使用pageHelper插件 做分页查询
        List<BusinessVO> vos = null;
        if (total>0){
            List<BusinessPO> pos =businessRepository.businessPage(query);
            //将pos 转换成vos 多对多的转换
            vos = pos.stream().map(po->{
                BusinessVO vo = new BusinessVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
*//*              for (BusinessPO po : pos){
               BusinessVO vo = new BusinessVO();
                BeanUtils.copyProperties(po,vo);
                 //vo添加到vos
              }
              *//*
        }
        voPages.setObjects(vos);
        log.info("分页查询结束：{}",voPages);
        return voPages;
    }*/

    public List<BusinessCategoryVO> getAllCats() {
        List<BusinessCategoryVO> vos = null;//如果没有数据查询结果
        //1、调用仓储层查询所有 分类数据pos
        List<BusinessCategoryPO> pos = businessCategoryRepository.getAll();
        //2、在pos不为空时，才封装vos
        if (CollectionUtils.isNotEmpty(pos)){
            vos = pos.stream().map(po->{
                BusinessCategoryVO vo = new BusinessCategoryVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        return vos;
    }

    //本地事务注解 会因为商家绑定图片失败抛的异常BusinessException回滚 新增商家不成功
    //注解默认回滚的异常范围是RuntimeException类型
    @Transactional(rollbackFor = Exception.class)
    public void businessSave(BusinessParam param)throws BusinessException {
        //1、检查是否当前登录用户是Admin角色
        checkRole(Roles.ADMIN);
        //2、考虑幂等 不允许重复提交 不允许名称和电话相同
        BusinessPO po=businessRepository.getBusinessByName(param.getBusinessName());
        //3、判断 经过if判断 满足表达式之后 抛异常--这种代码 叫做 断言 Assert
        Asserts.isTrue(po!=null,new BusinessException("-2","商家已经存在"));
        //4、封装数据 写入数据库新增商家--写入数据 业务层负责数据完整性
        //createTime businessStatus TODO
        BusinessPO poParam = businessParam2po(param);
        log.info("新增商家，新增前的id：{}",poParam.getId());
        //5、数据层写入数据 po是mybatis-plus框架 提供了注解 id会在新增后回填
        businessRepository.save(poParam);
        log.info("新增商家，新增后的id：{}",poParam.getId());
        //当前分布式事务场景 一致性属于强一致性 图片失败 导致商家新增回滚
        //选择消息事务 可以转换成 最终一致性
        // 6、新增商家之后 远程绑定图片
        bindPictures(poParam);
    }
    //6/
   @DubboReference
    private AttachApi attachApi;
    private void bindPictures(BusinessPO poParam) throws BusinessException {
        //1.根据poParam这个商家的数据 封装绑定图片的list
        //2.绑定几张 logo 营业执照 绑定给谁 当前商家 bizType=100 营业执照 bizType=200 logo bizId=businessId
        List<PicUpdateParam> picParams = new ArrayList<>();
        PicUpdateParam licencePic = new PicUpdateParam();
        licencePic.setBusinessId(poParam.getId());
        licencePic.setBusinessType(100);//100营业执照 商家的
        String licenseFileUuid = getFileUuidFromUrl(poParam.getBusinessLicense());
        licencePic.setFileUuid(licenseFileUuid);
        picParams.add(licencePic);
        //继续封装logo图片绑定参数
        PicUpdateParam logoPic = new PicUpdateParam();
        logoPic.setBusinessId(poParam.getId());
        logoPic.setBusinessType(200);//200是logo 商家的
        logoPic.setFileUuid(getFileUuidFromUrl(poParam.getBusinessLogo()));
        picParams.add(logoPic);
        //验证是否到此为止封装绑定图片数据正常
        log.info("当前商家：{}，绑定图片：{}",poParam.getBusinessName(),picParams);
        //发起远程调用
        boolean result = attachApi.batchUpdateBusiness(picParams);
        //对返回值的态度 考虑分布式事务问题 考虑数据一致 强一致性 图片绑定失败,新增商家 不增
        Asserts.isTrue(!result,new BusinessException("-2","图片绑定失败"));

    }
    private String getFileUuidFromUrl(String url) {
        //拿到图片id或者fileUuid 这里需要再数据库中找到url 截取fileUuid作为绑定入参
        //http://localhost:9081/static/liencesFileUuid
        String[] splists = url.split("/");
        return splists[splists.length-1];
    }

    //4、/
    private BusinessPO businessParam2po(BusinessParam param) {
        BusinessPO po = new BusinessPO();
        BeanUtils.copyProperties(param,po);
        //id 入参为空 不需要补充
        //businessName 入参文本框填写
        //industryType 行业类型 查询行业类型所选的id
        //businessHeadName  负责人 文本框
        //businessHeadPhone 负责人电话 文字框
        //companyAddress  公司地址 文本框
        //businessLicense  营业执照图片的url地址 文本框 上传完成图片后 前端将attach服务返回值补填
        //businessLogo 营业执照逻辑一样
        //没有 auditRemarks 没传 但是不需要填补 通过
        po.setAuditRemarks("通过");
        //没有 businessStatus 1待审核 2 通过 3驳回
        po.setBusinessStatus(2);
        po.setEntryTime(new Date());
        return po;
    }

    //1/
    private void checkRole(Roles roles)throws BusinessException {
        //直接使用断言 当前登录的用户角色 和业务需要的用户角色不相等 断言命中 抛异常
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户解析认证失败"));
        //获取登录用户的角色
        Roles loginRole = userPrinciple.getRole();
        Asserts.isTrue(loginRole!=roles,new BusinessException("-2","用户角色不符合要求"));
    }


    public BusiStoreVO businessStore(Integer id) throws BusinessException {
        //1.商家仓储层 查询商家
        BusinessPO businessPO = businessRepository.getBusiness(id);
        Asserts.isTrue(businessPO==null,new BusinessException("-2","商家不存在"));
        //2.使用商家id查询 所属的店铺列表
        List<StorePO> storePOS=storeRepository.getStoresByBizId(id);
        Asserts.isTrue(CollectionUtils.isEmpty(storePOS),new BusinessException("-2","不存在店铺"));
        //3.包装成vo返回
        BusiStoreVO vo=new BusiStoreVO();
        //拷贝
        BeanUtils.copyProperties(businessPO,vo);
        List<StoreVO> storeVOS = storePOS.stream().map(po -> {
            StoreVO storeVO = new StoreVO();
            BeanUtils.copyProperties(po, storeVO);
            return storeVO;
        }).collect(Collectors.toList());
        vo.setStoreVOList(storeVOS);
        return vo;
    }
}
